/*
 * Copyright 2009 Cedric Priscal
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android_serialport_api;

import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

import android_serialport_api.bean.CalculatePersonTempBean;
import android_serialport_api.bean.ReadAllBean;
import android_serialport_api.bean.TempConfigBean;
import de.greenrobot.event.EventBus;

/**
 * 身份证模块的  读写工具类
 */
public class ReadWriteTempUtil {
    private static ReadWriteTempUtil mInstance;

    public static ReadWriteTempUtil getInstance() {
        if (null == mInstance) {
            mInstance = new ReadWriteTempUtil();
        }
        return mInstance;
    }

    private ReadWriteTempUtil() {
        init();
    }

    //interrupt thread
    public void destroy() {
        if (mReadThread != null) {
            try {
                mReadThread.interrupt();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (null != mSerialPort) {
            mSerialPort.closeSerialPort();
            mSerialPort = null;
        }
        mInstance = null;
    }


    public static final String TAG = ReadWriteTempUtil.class.getSimpleName();
    protected SerialPort mSerialPort;
    protected OutputStream mOutputStream;
    private InputStream mInputStream;
    private ReadThread mReadThread;

    private class ReadThread extends Thread {

        @Override
        public void run() {
            while (!isInterrupted()) {
                try {
                    //一般来说，串口通信不会传递大量数据。 4096够用。
                    byte[] buffer = new byte[4096];
                    if (mInputStream == null) return;
                    int readCount = 0; //已经读取的总数目
                    int itemCount = mInputStream.read(buffer); //一次读取的字节数
                    int totalCount = getResultCount(buffer);
                    readCount = itemCount;
                    while (readCount < totalCount) {
                        itemCount = mInputStream.read(buffer, readCount, buffer.length - readCount);
                        readCount += itemCount;
                    }
                    parase_pkg(buffer);
                } catch (IOException e) {
                    Log.i("chuan2", e.toString() + "");
                    e.printStackTrace();
                    return;
                }
            }
        }
    }

    //根据开始的指令判断，一次应该读取多少数据
    //这个可以从指令说明文档获取
    private int getResultCount(byte[] buffer) {
        if (buffer[0] == 0x43 && buffer[1] == 0x4E) { //1查询配置
            return 37;
        }
        if (buffer[0] == 0x43 && buffer[1] == 0x46) { //2读取所有温度点
            return 2054;
        }
        if (buffer[0] == 0x43 && buffer[1] == 0x54) { //3计算人体温度
            return 10;
        }
        if (buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x3D) { //4设置发射率
            return 6;
        }
        return 0;
    }


    //字节转long
    private long getNum(byte[] arr, int start, int count) {
        long sumResult = 0L;
        if (count > 4) {
            throw new RuntimeException("count 不能超过4");
        }
        if (arr.length < start + count) {
            throw new RuntimeException("数组长度不够");
        }
        int tempIndex = start + count - 1;
        for (; tempIndex >= start; tempIndex--) {
            int itemNum = (arr[tempIndex] + 256) % 256;
            sumResult = (sumResult << 8) + itemNum;
        }
        return sumResult;
    }

    //整数转byte[]
    private byte[] int2Bytes(int num) {
        byte[] resultByte = new byte[4];
        resultByte[0] = (byte) (num & 0xFF);
        resultByte[1] = (byte) (num >> 8 & 0xFF);
        resultByte[2] = (byte) (num >> 16 & 0xFF);
        resultByte[3] = (byte) (num >> 24 & 0xFF);
        return resultByte;
    }

    //根据文档，解析数据
    void parase_pkg(byte[] buffer) {
        if (buffer[0] == 0x43 && buffer[1] == 0x4E) { //1查询配置
            long modelVersion = getNum(buffer, 2, 4);
            long sensorVersion = getNum(buffer, 6, 4);
            int deviceType = (int) getNum(buffer, 10, 2);
            int sendRate = (int) getNum(buffer, 29, 2);
            int firmwareVersion = (int) getNum(buffer, 33, 2);
            TempConfigBean tempConfigBean = new TempConfigBean(modelVersion, sensorVersion, deviceType, sendRate, firmwareVersion);
            EventBus.getDefault().post(new TempData(TempData.TYPE_READ_CONFIG, tempConfigBean));
            return;
        }
        if (buffer[0] == 0x43 && buffer[1] == 0x46) { //2读取所有温度点
            float[] temps = new float[1024];
            for (int i = 0; i < temps.length; i++) {
                int itemLower = (buffer[2 + (i * 2)] + 256) % 256;
                int itemHigher = (buffer[2 + (i * 2) + 1] + 256) % 256;
                float rawTemp = (itemHigher << 8) + itemLower;
                float temp = (rawTemp - 2731) / 10;
                temps[i] = temp;
            }

            int localLower = (buffer[2050] + 256) % 256;
            int localHigher = (buffer[2051] + 256) % 256;
            float rawTemp = (localHigher << 8) + localLower;
            float localTemp = (rawTemp - 2731) / 10;

            ReadAllBean readBean = new ReadAllBean(temps, localTemp);
            EventBus.getDefault().post(new TempData(TempData.TYPE_READ_ALL, readBean));
            return;
        }
        if (buffer[0] == 0x43 && buffer[1] == 0x54) { //3计算人体温度
            float temp = (float) (buffer[2] + (buffer[3] / 100.0));
            int xCoordinate = (int) getNum(buffer, 4, 2);
            int yCoordinate = (int) getNum(buffer, 6, 2);
            CalculatePersonTempBean calculatePersonTempBean = new CalculatePersonTempBean(temp, xCoordinate, yCoordinate);
            EventBus.getDefault().post(new TempData(TempData.TYPE_CALCULATE_PERSON, calculatePersonTempBean));
            return;
        }
        if (buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x3D) { //4设置发射率
            long modelNo = getNum(buffer, 2, 4);
            EventBus.getDefault().post(new TempData(TempData.TYPE_SET_SEND_RATE, modelNo));
            return;
        }

    }


    private void init() {
        try {
            mSerialPort = new SerialPort("/dev/ttyS1", 115200, 0);
            mOutputStream = mSerialPort.getOutputStream();
            mInputStream = mSerialPort.getInputStream();
            mReadThread = new ReadThread();
            mReadThread.start();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidParameterException e) {
            e.printStackTrace();
        }
    }

    //查询配置信息，发送的指令
    public void queryConfig() throws IOException {
        byte[] buf = {
                0x43, 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x54, 0x0D, 0x0A
        };
        mOutputStream.write(buf);
    }

    //读取所有温度点
    public void readAll() throws IOException {
        byte[] buf = {
                0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x0D, 0x0A
        };
        mOutputStream.write(buf);
    }

    //计算人体温度
    public void calculatePersonTemp() throws IOException {
        byte[] buf = {
                0x43, 0x61, 0x6C, 0x63, 0x54, 0x0D, 0x0A
        };
        mOutputStream.write(buf);
    }

    //设置发射率
    public void setSendRate(int sendRate) throws IOException {
        byte[] buf = {
                0x53, 0x65, 0x74, 0x45, 0x3D};
        byte[] rateBytes = int2Bytes(sendRate);
        for (int i = 0; i < rateBytes.length - 1; i++) {
            System.out.println(rateBytes[i]);
        }
        byte[] end = {0x0D, 0x0A};
        byte[] allByte = new byte[10];
        System.arraycopy(buf, 0, allByte, 0, buf.length);
        System.arraycopy(rateBytes, 0, allByte, 5, rateBytes.length - 1);
        System.arraycopy(end, 0, allByte, 8, end.length);
        mOutputStream.write(allByte);
    }

}
